#include "process_pool.h"

// 有序退出机制使用的管道
int exitfd[2];

void exitfunc(int sigNum)
{
    char flag = 1;
    write(exitfd[1], &flag, 1);
}

int start(int argc, char **argv)
{
    if (argc != 4)
    {
        printf("./process_pool ip port process_num\n");
        return -1;
    }

    int ret;
    pipe(exitfd);
    signal(SIGINT, exitfunc);

    // 创建子进程
    int process_num = atoi(argv[3]);
    process_data_t *p_manage = (process_data_t *)calloc(process_num, sizeof(process_data_t)); // p_manage用来管理所有子进程信息
    make_child(p_manage, process_num);
    
    // 初始化tcp连接listen
    int socket_fd;
    ret = tcp_init(&socket_fd, argv[1], argv[2]);
    SELFFUNC_ERR_CHECK(ret, "tcp_init");   
    printf("socket_fd = %d\n", socket_fd);

    // 主进程epoll监控是否有新clinet连接和是否有子进程空闲
    int epfd = epoll_create(1);
    ret = epoll_add(epfd, socket_fd);
    SELFFUNC_ERR_CHECK(ret, "epoll_add");
    ret = epoll_add(epfd, exitfd[0]);
    SELFFUNC_ERR_CHECK(ret, "epoll_add");
    for (int i = 0; i < process_num; i ++) // 把全部子进程fd加入到epoll红黑树中
    {
        ret = epoll_add(epfd, p_manage[i].fd);
        SELFFUNC_ERR_CHECK(ret, "epoll_add");
    }

    int ready_fd_num;
    while(1)
    {
        struct epoll_event *evs = (struct epoll_event *)calloc(process_num + 1, sizeof(struct epoll_event)); // 一共是process_num + 1(socket_fd)个event
        ready_fd_num = epoll_wait(epfd, evs, process_num + 1, -1);
        struct sockaddr_in client_addr; // 客户端信息结构体
        for (int i = 0; i < ready_fd_num; i ++)
        {
            // 1. 有client连接
            if (evs[i].data.fd == socket_fd)
            {
                bzero(&client_addr, sizeof(client_addr));
                int addr_len = sizeof(client_addr);
                int new_fd = accept(socket_fd, (struct sockaddr *)&client_addr, &addr_len);
                printf("client %s %d connect success\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                
                // 找到不忙碌的子进程
                for (int j = 0; j < process_num; j ++)
                {
                    if (p_manage[j].busy == 0)
                    {
                        send_fd(p_manage[j].fd, new_fd, 0); // 将客户端fd发送给子进程
                        p_manage[j].busy = 1;
                        printf("child %d is busy\n", p_manage[j].pid);
                        break;
                    }
                }
                close(new_fd); // 无论是否找到空闲子进程，都关闭
            }

            // 如果收到子进程的通知，表示服务完成，将它设置为不忙碌
            for (int j = 0; j < process_num; j ++)
            {
                if (evs[i].data.fd == p_manage[j].fd)
                {
                    char flag;
                    read(p_manage[j].fd, &flag, sizeof(flag));
                    p_manage[j].busy = 0;
                    printf("child %d is not busy\n",p_manage[j].pid);
                    break;
                }
            }

            // 收到退出信号，通知子线程退出
            if (evs[i].data.fd == exitfd[0])
            {
                for (int j = 0; j < process_num; j ++)
                {
                    send_fd(p_manage[j].fd, STDIN_FILENO, 1);
                    
                }
                for (int j = 0; j < process_num; j ++)
                {
                    wait(NULL); // 回收每一个子进程
                }
                close(socket_fd);
            }
        }
    }
}

int main(int argc, char **argv)
{
    while (1)
    {
        pid_t pid = fork();

        if (pid == 0)
        {
            start(argc, argv);
            return 0;
        } else {
            int status;
            wait(&status);
            if (WIFEXITED(status))
            {
                exit(0);
            } else {
                printf("server crush, start again\n");
            }
        }
    }   
}